//
//  BlurBackgroudNode.cpp
//  client
//
//  Created by will on 01/11/2017.
//
//

#include "BlurBackgroudNode.hpp"

using namespace cocos2d;

BlurBackgroudNode* BlurBackgroudNode::create()
{
    auto ret = new (std::nothrow) BlurBackgroudNode();
    if(ret->init())
    {
        ret->autorelease();
        return ret;
    }
    return nullptr;
}

bool BlurBackgroudNode::init()
{
    if(Layout::init())
    {
        _blurProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_BLUR);
        return true;
    }
    return false;
}

BlurBackgroudNode::BlurBackgroudNode()
:_blurProgram(nullptr)
,_target(nullptr)
,_rendered(false)
,_delegate(nullptr)
{
    
}

BlurBackgroudNode::~BlurBackgroudNode()
{
}

void BlurBackgroudNode::setBlurTargetNode(cocos2d::Node* target)
{
    _target = target;
}

void BlurBackgroudNode::setEventCallback(const EventFuntion& func)
{
    _delegate = func;
}

void BlurBackgroudNode::drawFBOTexture(const cocos2d::Mat4 &mat4)
{
    Director* director = Director::getInstance();
    
    auto screenSize = director->getWinSizeInPixels();
    
    auto fboTexture = director->getRenderer()->getFBOTexture();
    fboTexture->setGLProgram(_blurProgram);
    
    auto blendFunc = BlendFunc::ALPHA_PREMULTIPLIED;
    GL::blendFunc(blendFunc.src,blendFunc.dst);
    
    CHECK_GL_ERROR_DEBUG();
    
    fboTexture->drawInRect(Rect(0, 0, screenSize.width, screenSize.height),Color4F::WHITE, true,[this,fboTexture](){
        auto radiusValue = _blurProgram->getUniform("u_radius");
        if(radiusValue)
        {
            _blurProgram->setUniformLocationWith1f(radiusValue->location, 4.0f);
        }
        
        auto resolutionValue = _blurProgram->getUniform("u_resolution");
        if(resolutionValue)
        {
            _blurProgram->setUniformLocationWith2f(resolutionValue->location, fboTexture->getPixelsWide(),fboTexture->getPixelsHigh());
        }
    });
    
}

void BlurBackgroudNode::captureTarget()
{
    if(_delegate)
    {
        _delegate(true);
    }
    Director* director = Director::getInstance();
    
    _fboCommand.init(_globalZOrder,nullptr,nullptr);
    auto renderer = director->getRenderer();
    renderer->addCommand(&_fboCommand);
    renderer->pushGroup(_fboCommand.getRenderQueueID());
    
    _target->retain();
    _target->visit();
    _target->release();
    
    renderer->popGroup();
    
    if(_delegate)
    {
        _delegate(false);
    }
}

void BlurBackgroudNode::visit(cocos2d::Renderer* renderer, const cocos2d::Mat4 &parentTransform, uint32_t parentFlags)
{
    //capture target to FBO buffer once
    if(!_rendered && _target && isVisible())
    {
        _rendered = true;
        captureTarget();
        _target = nullptr;
    }
    
    
    if(_rendered && !_target)
    {
        //draw FBO Texture with blur effect
        if(isVisible())
        {
            _drawCommand.init(_globalZOrder,parentTransform,parentFlags);
            _drawCommand.func = [this,parentTransform](){
                this->drawFBOTexture(parentTransform);
            };
            renderer->addCommand(&_drawCommand);
        }
    }
    
    Layout::visit(renderer, parentTransform, parentFlags);
}
